<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务，帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2024 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件，不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);

namespace app\api\model\store;

use app\common\model\store\Shop as ShopModel;

/**
 * 商家门店模型
 * Class Shop
 * @package app\store\model\store
 */
class Shop extends ShopModel
{
    /**
     * 隐藏字段
     * @var array
     */
    protected $hidden = [
        'is_delete',
        'store_id',
        'create_time',
        'update_time'
    ];

    /**
     * 获取门店列表
     * @param array $param 查询参数
     * @param int|null $limit 查询条数
     * @return array|\think\Collection
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getList(array $param = [], int $limit = null)
    {
        // 查询构造器
        $query = $this->getNewQuery();
        // 设置列表查询条件
        $filter = $this->getFilter($param);
        // 获取数量
        $limit > 0 && $query->limit($limit);
        // 获取门店列表数据
        $list = $query->with(['logoImage'])
            ->where($filter)
            ->where('is_delete', '=', 0)
            ->where('status', '=', 1)
            ->order(['sort' => 'asc', $this->getPk()])
            ->select();
        // 根据距离排序
        if (!empty($param['longitude']) && !empty($param['latitude'])) {
            return $this->sortByDistance($list, $param['longitude'], $param['latitude']);
        }
        return $list;
    }

    /**
     * 设置列表查询条件
     * @param array $param
     * @return array
     */
    private function getFilter(array $param = []): array
    {
        // 默认查询参数
        $params = $this->setQueryDefaultValue($param, [
            'isCheck' => -1,   // 是否支持自提核销(0否 1支持)
            'longitude' => '',     // 用户位置: 经度
            'latitude' => '',     // 用户位置: 纬度
        ]);
        // 检索查询条件
        $filter = [];
        // 是否支持自提核销
        $params['isCheck'] > -1 && $filter[] = ['is_check', '=', (int)$params['isCheck']];
        return $filter;
    }

    /**
     * 根据距离排序
     * @param $data
     * @param string $longitude 经度
     * @param string $latitude 纬度
     * @return array
     */
    private function sortByDistance($data, string $longitude, string $latitude): array
    {
        // 根据距离排序
        $list = $data->isEmpty() ? [] : $data->toArray();
        $sortArr = [];
        foreach ($list as &$shop) {
            // 计算距离
            $distance = self::getDistance((float)$longitude, (float)$latitude, (float)$shop['longitude'], (float)$shop['latitude']);
            // 排序列
            $sortArr[] = $distance;
            $shop['distance'] = $distance;
            if ($distance >= 1000) {
                $distance = bcdiv((string)$distance, (string)1000, 2);
                $shop['distance_unit'] = $distance . 'km';
            } else
                $shop['distance_unit'] = $distance . 'm';
        }
        // 根据距离排序
        array_multisort($sortArr, SORT_ASC, $list);
        return $list;
    }

    /**
     * 获取两个坐标点的距离
     * @param float $ulon
     * @param float $ulat
     * @param float $slon
     * @param float $slat
     * @return float
     */
    private static function getDistance(float $ulon, float $ulat, float $slon, float $slat): float
    {
        // 地球半径
        $R = 6378137;
        // 将角度转为狐度
        $radLat1 = deg2rad($ulat);
        $radLat2 = deg2rad($slat);
        $radLng1 = deg2rad($ulon);
        $radLng2 = deg2rad($slon);
        // 结果
        $s = acos(cos($radLat1) * cos($radLat2) * cos($radLng1 - $radLng2) + sin($radLat1) * sin($radLat2)) * $R;
        // 精度
        $s = round($s * 10000) / 10000;
        return round($s);
    }

    /**
     * 根据门店id集获取门店列表
     * @param array $shopIds
     * @return \think\Collection|false
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getListByIds(array $shopIds)
    {
        if (empty($shopIds)) {
            return false;
        }
        // 筛选条件
        $filter = [['shop_id', 'in', $shopIds]];
        // 获取商品列表数据
        return $this->with(['logoImage'])
            ->orderRaw('field(shop_id, ' . implode(',', $shopIds) . ')')
            ->where('is_delete', '=', '0')
            ->where('status', '=', '1')
            ->where($filter)
            ->select();
    }
}